/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024.
 * Description: support expedited message handling,The logic of the icmpv6_err function is modified
 * Author: Chen Zechuan
 * Create: 2023/9/15
 */

#ifdef CONFIG_ONT_CHECK_ICMPV6_MTU
static bool (*g_icmpv6_check_mtu)(__be32 mtu);

void icmpv6_set_mtu_checking_hook(typeof(g_icmpv6_check_mtu) hook)
{
	typeof(g_icmpv6_check_mtu) cur_hook = NULL;

	rcu_read_lock();
	cur_hook = rcu_dereference(g_icmpv6_check_mtu);
	if ((cur_hook && hook) || (!cur_hook && !hook)) {
		rcu_read_unlock();
		pr_err("repeatedly setting mtu_checking_hook\n");
		return;
	}
	rcu_read_unlock();

	rcu_assign_pointer(g_icmpv6_check_mtu, hook);
}
EXPORT_SYMBOL(icmpv6_set_mtu_checking_hook);
#endif

#ifdef CONFIG_RTOS_NET_ICPMV6_ERR_CONDITION
static inline bool is_ipv6_addr_linklocal(struct sk_buff *skb)
{
	struct ipv6hdr *hdr = ipv6_hdr(skb);
	unsigned int addr_type = (unsigned int)ipv6_addr_type(&hdr->daddr);
	return !(addr_type & IPV6_ADDR_LINKLOCAL);
}
#endif

static inline bool ip6_pmtu_need_update(struct sk_buff *skb, __be32 mtu)
{
	bool ret = true;
#ifdef CONFIG_ONT_CHECK_ICMPV6_MTU
	typeof(g_icmpv6_check_mtu) cur_hook = NULL;

	rcu_read_lock();
	cur_hook = rcu_dereference(g_icmpv6_check_mtu);
	if (cur_hook) {
		ret = cur_hook(mtu);
		rcu_read_unlock();
		return ret;
	}
	rcu_read_unlock();
#endif

#ifdef CONFIG_RTOS_NET_ICPMV6_ERR_CONDITION
	ret = is_ipv6_addr_linklocal(skb);
#endif
	return ret;
}
